using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Media.Imaging;
using 修为尽失.辅助.exts;

namespace 修为尽失.辅助
{
    public class IOHelper
    {
         private static readonly char[] _InvalidChars = Path.GetInvalidFileNameChars();
        private static readonly char[] InvalidPathChars = new char[39] {'"', '<', '>', '|', char.MinValue, '\x0001', '\x0002', '\x0003', '\x0004', '\x0005', '\x0006', '\a', '\b', '\t', '\n', '\v', '\f', '\r', '\x000E', '\x000F', '\x0010', '\x0011', '\x0012', '\x0013', '\x0014', '\x0015', '\x0016', '\x0017', '\x0018', '\x0019', '\x001A', '\x001B', '\x001C', '\x001D', '\x001E', '\x001F', '*', '?', ':'};

        #region 专用

        public static Dictionary<string, Type[]> LoadPlugins(string dir)
        {
            if (!Directory.Exists(dir))
                return null;
            string[] files = Directory.GetFiles(dir, "*.more");
            var dic = new Dictionary<string, Type[]>();
            foreach (string f in files)
            {
                try
                {
                    Assembly a = Assembly.LoadFrom(f);
                    dic.Add(f, a.GetTypes());
                }
                catch (Exception e)
                {
                   e.ShowException();
                }
            }

            return dic;
        }

        public static void AddMoePictureToDictionary(SortedDictionary<int, string> sd, string p, string site)
        {
            var name = Path.GetFileNameWithoutExtension(p);
            var parts = name?.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
            if (parts?.Length > 1 && name.StartsWith(site) && int.TryParse(parts[1], out int id) && !sd.ContainsKey(id))
            {
                sd.Add(id,p);
            }
        }

        public static void AddMoePictureToDictionary(System.Collections.Concurrent.ConcurrentDictionary<int, string> sd, string p, string site)
        {
            var name = Path.GetFileNameWithoutExtension(p);
            var parts = name?.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
            if (parts?.Length > 1 && name.StartsWith(site) && int.TryParse(parts[1], out int id))
            {
                sd.TryAdd(id, p);
            }
        }

        #endregion

        #region 通用

        public static string ConnectPath(params string[] path) => ConnectPath('\\', path);

        public static string ConnectPath(char separate, params string[] path)
        {
            if (((IEnumerable<string>) path).IsInvalid<string>())
                return string.Empty;
            if (path.Length == 2)
                return $"{(object) path[0].TrimEnd(separate)}{(object) separate}{(object) path[1].TrimStart(separate)}";
            if (path.Length == 1)
                return path[0];
            var stringBuilder = new StringBuilder(32);
            foreach (var str in path)
                stringBuilder.Append(str.TrimEnd(separate).TrimStart(separate)).Append(separate);
            return stringBuilder.ToString().TrimEnd(separate);
        }

        public static string ConvertLinuxPath(string linuxpath, char validChar = '_')
        {
            var index = linuxpath.IndexOfAny(InvalidPathChars);
            if (index >= 0)
                return ConvertLinuxPath(linuxpath.Replace(linuxpath[index], validChar), '_');
            return linuxpath.Replace('/', '\\');
        }

        public static void CreateDirectory(string directoryPath)
        {
            if (string.IsNullOrEmpty(directoryPath) || Directory.Exists(directoryPath))
                return;
            Executer.TryRunLogExceptioin((Action) (() => Directory.CreateDirectory(directoryPath)), $"文件夹{(object) directoryPath}创建失败");
        }

        public static void CreateFile(string filePath, byte[] buffer)
        {
            if (string.IsNullOrEmpty(filePath))
                return;
            try
            {
                if (!System.IO.File.Exists(filePath))
                {
                    using (var fileStream = new FileInfo(filePath).Create()) fileStream.Write(buffer, 0, buffer.Length);
                }
            }
            catch
            {
            }
        }

        public static void CreateFile(string filePath, string text) => CreateFile(filePath, text, Encoding.GetEncoding("utf-8"));

        public static void CreateFile(string filePath, string text, Encoding encoding)
        {
            if (string.IsNullOrEmpty(filePath))
                return;
            var filePath1 = GetFilePath(filePath, '\\');
            if (!Directory.Exists(filePath1))
                Directory.CreateDirectory(filePath1);
            using (var fileStream = new FileInfo(filePath).Create())
            {
                using (var streamWriter = new StreamWriter((Stream) fileStream, encoding))
                {
                    streamWriter.Write(text);
                    streamWriter.Flush();
                }
            }
        }

        public static string CreateFileDirectory(string filePath)
        {
            var filePath1 = GetFilePath(filePath, '\\');
            CreateDirectory(filePath1);
            return filePath1;
        }

        public static void DeleteFile(string filePath)
        {
            if (filePath.IsInvalid())
                return;
            try
            {
                System.IO.File.Delete(filePath);
            }
            catch (Exception ex)
            {
                throw new Exception("删除文件异常:" + filePath, ex);
            }
        }

        public static byte[] FileToBytes(string filePath, int len = 0, int start = 0)
        {
            using (var stream = FileToStream(filePath))
            {
                var num1 = stream.Length > (long) int.MaxValue ? int.MaxValue : (int) stream.Length;
                var num2 = len           == 0 ? num1 : len;
                var count = num2         >= num1 ? num1 : num2;
                var buffer = new byte[count];
                stream.Read(buffer, start, count);
                return buffer;
            }
        }

        public static FileStream FileToStream(string path)
        {
            Guard.ArgumentNotNullOrEmpty(path, nameof(path));
            return new FileStream(path, FileMode.Open, FileAccess.Read);
        }

        public static string FileToString(string filePath) => FileToString(filePath, Encoding.UTF8);

        public static string FileToString(string filePath, Encoding encoding)
        {
            if (!System.IO.File.Exists(filePath))
                return string.Empty;
            try
            {
                using (var streamReader = new StreamReader(filePath, encoding)) return streamReader.ReadToEnd();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static string FilterInvalidFileName(string oriName) => _InvalidChars.Aggregate(oriName, (current, invalidChar) => current.Replace(invalidChar.ToString(), string.Empty));

        public static string GetFileExtension(string file)
        {
            var length = file.Length;
            var startIndex = length;
            while (--startIndex >= 0)
            {
                var ch = file[startIndex];
                if ((int) ch == 46)
                    return file.Substring(startIndex, length - startIndex);
                if ((int) ch == (int) Path.DirectorySeparatorChar || (int) ch == (int) Path.AltDirectorySeparatorChar || (int) ch == (int) Path.VolumeSeparatorChar)
                    break;
            }

            return string.Empty;
        }

        public static long GetFileLength(string filepath)
        {
            long num = 0;
            using (var fileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read))
                num = fileStream.Length;
            return num;
        }

        public static string GetFileName(string source, char separate = '\\')
        {
            if (source.IsInvalid())
                return string.Empty;
            source = source.TrimEnd(separate);
            var num = source.LastIndexOf(separate);
            if (num > 0)
                return source.Substring(num + 1, source.Length - num - 1);
            return source;
        }

        public static string GetFilePath(string source, char separate = '\\')
        {
            if (source.IsInvalid())
                return string.Empty;
            source = source.TrimEnd(separate);
            var num = source.LastIndexOf(separate);
            if (num > 0)
                return source.Substring(0, num + 1);
            return source;
        }

        public static IList<FileInfo> GetFiles(string folder, string extension) => GetFiles(folder, new string[1] {extension});

        public static IList<FileInfo> GetFiles(string folder, string[] extensions) => (IList<FileInfo>) ((IEnumerable<string>) Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories)).Select(file =>
        {
            var data = new {file, extension = Path.GetExtension(file)};
            return data;
        }).Where(_param1 => _param1.extension != null && ((IEnumerable<string>) extensions).Contains<string>(_param1.extension.ToLower())).Select(_param0 => new FileInfo(_param0.file)).ToList<FileInfo>();

        public static string AutoBytes(string filePath)
        {
            Guard.ArgumentNotNullOrEmpty(filePath, nameof(filePath));
            if (!System.IO.File.Exists(filePath))
                return string.Empty;
            return AutoBytes(new FileInfo(filePath).Length, "F2");
        }

        public static string AutoBytes(int len) => AutoBytes(len, "F2");

        public static string AutoBytes(long len, string format = "F2")
        {
            if (len <= 0L)
                return "0 KB";
            var str = " B";
            var d = (double) len;
            var num = 1024.0d;
            if (len >= num)
            {
                d = len / num;
                str = " KB";
            }

            if (d > num)
            {
                d /= num;
                str = " MB";
            }

            if (d > num)
            {
                d /= num;
                str = " GB";
            }

            if (d                         - Math.Truncate(d) == 0.0)
                return d.ToString(format) + str;
            return d.ToString(format) + str;
        }

        public static int GetMoePictureID(string fullpath)
        {
            var parts = Path.GetFileName(fullpath)?.Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries);
            var a = 0;
            if (int.TryParse(parts[1], out a))
                return a;
            return -1;
        }

        public static string GetPhysicalPath(string relativePath)
        {
            if (string.IsNullOrEmpty(relativePath))
                return string.Empty;
            relativePath = relativePath.Replace("/", "\\").Replace("~", string.Empty).Replace("~/", string.Empty);
            relativePath = relativePath.StartsWith("\\") ? relativePath.Substring(1, relativePath.Length - 1) : relativePath;
            return Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, relativePath);
        }

        public static bool InputPathIsValid(string path) => IsPositiveNumber(path) && HasUninvalidPathChars(path);

        public static bool IsFileInUsing(string path)
        {
            var flag = true;
            try
            {
                using (new FileStream(path, FileMode.Open)) flag = false;
            }
            catch
            {
            }

            return flag;
        }

        public static bool IsValid(string file) => !file.IsInvalid() && System.IO.File.Exists(file) && new FileInfo(file).Length > 0L;
        public static bool IsValidDictory(string path) => !path.IsInvalid()                         && Directory.Exists(path);
        public static Bitmap LoadBitmap(string filename) => new Bitmap(LoadImage(filename));

        public static BitmapImage LoadBitmapImage(string imagePath)
        {
            var bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.CacheOption = BitmapCacheOption.OnLoad;
            using (Stream ms = new MemoryStream(System.IO.File.ReadAllBytes(imagePath)))
            {
                bitmap.StreamSource = ms;
                bitmap.EndInit();
                bitmap.Freeze();
            }

            return bitmap;
        }

        public static Image LoadImage(string filename)
        {
            var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            var byteLength = (int) fileStream.Length;
            var fileBytes = new byte[byteLength];
            fileStream.Read(fileBytes, 0, byteLength);
            fileStream.Close();
            return Image.FromStream(new MemoryStream(fileBytes));
        }

        public static void Open(params string[] path)
        {
            if (((IEnumerable<string>) path).IsInvalid<string>())
                return;
            var arguments = ConnectPath(path);
            try
            {
                Process.Start("explorer.exe", arguments);
            }
            catch (Exception ex)
            {
                throw new Exception("打开文件出现异常:" + arguments, ex);
            }
        }

        public static Bitmap OpenConvertToBitmap(string filename)
        {
            var ms = new MemoryStream();
            LoadImage(filename).Save(ms, ImageFormat.Bmp);
            return new Bitmap(ms);
        }

        public static byte[] ReadFileHead(string filePath, int index = 4)
        {
            using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                var buffer = new byte[index];
                fileStream.Read(buffer, 0, index);
                return buffer;
            }
        }

        public static string TryGetExtension(string filename, char splitChar)
        {
            Guard.ArgumentNotNullOrEmpty(filename, "filePath");
            var strArray = filename.Split(splitChar);
            var str = string.Empty;
            if (((IEnumerable<string>) strArray).Any<string>())
                str = ((IEnumerable<string>) strArray).Last<string>();
            return str;
        }

        private static bool HasUninvalidPathChars(string path) => !Path.GetInvalidPathChars().Any((Func<char, bool>) path.Contains<char>);
        private static bool IsPositiveNumber(string path) => Regex.IsMatch(path, "^[a-zA-Z]:\\\\[^\\/\\:\\*\\?\\\"\\<\\>\\|\\,]+$", RegexOptions.IgnoreCase);

        #endregion
    }
}